from __future__ import annotations

from dataclasses import dataclass
from datetime import date
from typing import Optional

from lunardate import LunarDate  # type: ignore


CN_NUM = {
    '零': 0,
    '〇': 0,
    '一': 1, '二': 2, '三': 3, '四': 4, '五': 5,
    '六': 6, '七': 7, '八': 8, '九': 9,
    '十': 10, '廿': 20, '卅': 30,
}

MONTH_ALIASES = {
    '正月': 1,
    '冬月': 11,
    '腊月': 12,
}


def _parse_cn_day(text: str) -> Optional[int]:
    # 形如 初五/初十/十一/廿五/二十/三十
    t = text.strip()
    if not t:
        return None
    t = t.replace('初', '')
    if t in ('十', '廿', '卅'):
        return CN_NUM[t]
    # 处理十X、廿X
    if t.startswith('十') and len(t) > 1:
        return 10 + CN_NUM.get(t[1], 0)
    if t.startswith('廿') and len(t) > 1:
        return 20 + CN_NUM.get(t[1], 0)
    if t == '三十':
        return 30
    # 二十六、二十三
    total = 0
    i = 0
    while i < len(t):
        ch = t[i]
        if ch == '十':
            total = (total or 1) * 10
        else:
            total += CN_NUM.get(ch, 0)
        i += 1
    return total or None


def _parse_cn_month(text: str) -> tuple[Optional[int], bool]:
    # 返回(月, 是否闰月)
    t = text.strip()
    leap = False
    if t.startswith('闰'):
        leap = True
        t = t[1:]
    if t in MONTH_ALIASES:
        return MONTH_ALIASES[t], leap
    if t.endswith('月'):
        t = t[:-1]
    # 一月、十一月 等
    if t == '十':
        return 10, leap
    if t.startswith('十') and len(t) > 1:
        n = 10 + CN_NUM.get(t[1], 0)
        return (n if 1 <= n <= 12 else None), leap
    if len(t) == 2 and t[0] in CN_NUM and t[1] in CN_NUM:
        n = CN_NUM[t[0]] * 10 + CN_NUM[t[1]]
        return (n if 1 <= n <= 12 else None), leap
    n = CN_NUM.get(t)
    return (n if n and 1 <= n <= 12 else None), leap


@dataclass
class LunarPattern:
    month: int
    day: int
    leap: bool = False


def parse_lunar_str(s: str) -> Optional[LunarPattern]:
    if not s:
        return None
    s = s.strip()
    # 常见格式：闰三月初五 / 正月初五 / 腊月二十六 / 十一月二十
    # 简单切分：找到“月”字
    try:
        idx = s.index('月')
    except ValueError:
        # 可能省略“月”：如“腊月初八”已处理；没有“月”则无法解析
        return None
    m_text = s[: idx + 1]
    d_text = s[idx + 1 :]
    month, leap = _parse_cn_month(m_text)
    day = _parse_cn_day(d_text)
    if month and day:
        return LunarPattern(month=month, day=day, leap=leap)
    return None


def lunar_to_solar(year: int, pattern: LunarPattern) -> Optional[date]:
    try:
        ld = LunarDate(year, pattern.month, pattern.day, pattern.leap)
        return ld.toSolarDate()
    except Exception:
        return None


def next_solar_from_lunar(pattern: LunarPattern, reference: date) -> Optional[date]:
    # 尝试今年，否则明年
    for y in (reference.year, reference.year + 1):
        d = lunar_to_solar(y, pattern)
        if d and d >= reference:
            return d
    # 兜底再往后一年
    d = lunar_to_solar(reference.year + 2, pattern)
    return d

